/**
 * 检查图片是否有被压扁，如果有，返回比率
 * ref to http://stackoverflow.com/questions/11929099/html5-canvas-drawimage-ratio-bug-ios
 */
function detectVerticalSquash (img) {
  // 拍照在IOS7或以下的机型会出现照片被压扁的bug
  let data
  let ih = img.naturalHeight
  let canvas = document.createElement('canvas')
  canvas.width = 1
  canvas.height = ih
  let ctx = canvas.getContext('2d')
  ctx.drawImage(img, 0, 0)
  try {
    data = ctx.getImageData(0, 0, 1, ih).data
  } catch (err) {
    console.log('Cannot check verticalSquash: CORS?')
    return 1
  }
  let sy = 0
  let ey = ih
  let py = ih
  while (py > sy) {
    let alpha = data[(py - 1) * 4 + 3]
    if (alpha === 0) {
      ey = py
    } else {
      sy = py
    }
    py = (ey + sy) >> 1 // py = parseInt((ey + sy) / 2)
  }
  let ratio = (py / ih)
  return (ratio === 0) ? 1 : ratio
}

/**
* dataURI to blob, ref to https://gist.github.com/fupslot/5015897
* @param dataURI
*/
function dataURItoBuffer (dataURI) {
  let byteString = atob(dataURI.split(',')[1])
  let buffer = new ArrayBuffer(byteString.length)
  let view = new Uint8Array(buffer)
  for (let i = 0; i < byteString.length; i++) {
    view[i] = byteString.charCodeAt(i)
  }
  return buffer
}
function dataURItoBlob (dataURI) {
  let mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
  let buffer = dataURItoBuffer(dataURI)
  return new Blob([buffer], { type: mimeString })
}

/**
* 获取图片的orientation
* ref to http://stackoverflow.com/questions/7584794/accessing-jpeg-exif-rotation-data-in-javascript-on-the-client-side
*/
function getOrientation (buffer) {
  let view = new DataView(buffer)
  if (view.getUint16(0, false) !== 0xFFD8) return -2
  let length = view.byteLength
  let offset = 2
  while (offset < length) {
    let marker = view.getUint16(offset, false)
    offset += 2
    if (marker === 0xFFE1) {
      if (view.getUint32(offset += 2, false) !== 0x45786966) return -1
      let little = view.getUint16(offset += 6, false) === 0x4949
      offset += view.getUint32(offset + 4, little)
      let tags = view.getUint16(offset, little)
      offset += 2
      for (let i = 0; i < tags; i++) {
        if (view.getUint16(offset + (i * 12), little) === 0x0112) { return view.getUint16(offset + (i * 12) + 8, little) }
      }
    } else if ((marker & 0xFF00) !== 0xFF00) break
    else offset += view.getUint16(offset, false)
  }
  return -1
}

/**
* 修正拍照时图片的方向
* ref to http://stackoverflow.com/questions/19463126/how-to-draw-photo-with-correct-orientation-in-canvas-after-capture-photo-by-usin
*/
function orientationHelper (canvas, ctx, orientation) {
  const w = canvas.width
  const h = canvas.height
  if (orientation > 4) {
    canvas.width = h
    canvas.height = w
  }
  switch (orientation) {
    case 2:
      ctx.translate(w, 0)
      ctx.scale(-1, 1)
      break
    case 3:
      ctx.translate(w, h)
      ctx.rotate(Math.PI)
      break
    case 4:
      ctx.translate(0, h)
      ctx.scale(1, -1)
      break
    case 5:
      ctx.rotate(0.5 * Math.PI)
      ctx.scale(1, -1)
      break
    case 6:
      ctx.rotate(0.5 * Math.PI)
      ctx.translate(0, -h)
      break
    case 7:
      ctx.rotate(0.5 * Math.PI)
      ctx.translate(w, -h)
      ctx.scale(-1, 1)
      break
    case 8:
      ctx.rotate(-0.5 * Math.PI)
      ctx.translate(-w, 0)
      break
  }
}

/**
 * 压缩图片
 * @param {Object} file
 * @param {Object} options
 * @param {String} [options.type=file] 上传类型, `file`为文件上传; `base64`为以base64上传
 * @param {Boolean} [options.compress] 压缩配置, `false`则不压缩
 * @param {Number} [options.width=1600] 图片的最大宽度
 * @param {Number} [options.height=1600] 图片的最大高度
 * @param {Number} [options.quality=.8] 压缩质量, 取值范围 0 ~ 1
 */
export function compress (file, options = {}) {
  options = Object.assign({
    type: 'file',
    compress: true,
    width: 1600,
    height: 1600,
    quality: 0.8
  }, options)
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.onload = function (evt) {
      if (options.compress === false) {
        // 不启用压缩 & base64上传 的分支，不做任何处理，直接返回文件的base64编码
        file.base64 = evt.target.result
        // callback(file)
        resolve(file)
        return
      }

      // 启用压缩的分支
      const img = new Image()
      img.onload = function () {
        const ratio = detectVerticalSquash(img)
        const orientation = getOrientation(dataURItoBuffer(img.src))
        const canvas = document.createElement('canvas')
        const ctx = canvas.getContext('2d')

        const maxW = options.width
        const maxH = options.height
        let w = img.width
        let h = img.height
        let dataURL

        if (w < h && h > maxH) {
          w = parseInt(maxH * img.width / img.height)
          h = maxH
        } else if (w >= h && w > maxW) {
          h = parseInt(maxW * img.height / img.width)
          w = maxW
        }

        canvas.width = w
        canvas.height = h

        if (orientation > 0) {
          orientationHelper(canvas, ctx, orientation)
        }
        ctx.drawImage(img, 0, 0, w, h / ratio)

        if (/image\/jpeg/.test(file.type) || /image\/jpg/.test(file.type)) {
          dataURL = canvas.toDataURL('image/jpeg', options.quality)
        } else {
          dataURL = canvas.toDataURL(file.type)
        }

        if (options.type === 'file') {
          if (/;base64,null/.test(dataURL) || /;base64,$/.test(dataURL)) {
            // 压缩出错，以文件方式上传的，采用原文件上传
            console.warn('Compress fail, dataURL is ' + dataURL + '. Next will use origin file to upload.')
            // callback(file)
            resolve(file)
          } else {
            let blob = dataURItoBlob(dataURL)
            blob.name = file.name
            blob.lastModified = file.lastModified
            blob.lastModifiedDate = file.lastModifiedDate
            // callback(blob)
            resolve(blob)
          }
        } else {
          if (/;base64,null/.test(dataURL) || /;base64,$/.test(dataURL)) {
            // 压缩失败，以base64上传的，直接报错不上传
            // options.onError(file, new Error('Compress fail, dataURL is ' + dataURL + '.'))
            // callback()
            reject(new Error('Compress fail, dataURL is ' + dataURL + '.'))
          } else {
            file.base64 = dataURL
            // callback(file)
            resolve(file)
          }
        }
      }
      img.src = evt.target.result
    }
    reader.readAsDataURL(file)
  })
}
